﻿using IOP.SgrA;
using IOP.SgrA.SilkNet.Vulkan;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.KHR;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Text;

namespace VkSample102
{
    public class Startup : ISgrAStartup
    {
        public Startup()
        {
        }

        public void Configure(IGraphicsBuilder server, IHostEnvironment env)
        {
            server.BuildVulkan((manager) =>
            {
                manager.CreateVulkanInstanceFromConfiguration().CreateDebugReportCallback(DebugReport);
                manager.Logger.LogInformation("创建Vulkan实例成功");
                manager.Logger.LogInformation($"Vulkan硬件设备数量为{manager.PhysicalDevices.Length}个");

                var pDevice = manager.PhysicalDevices[0];
                var lDevice = manager.CreateVulkanDevice(pDevice, (device) =>
                {
                    device.Name = "main";
                    device.EnabledExtensionNames = new string[] { KhrSwapchain.ExtensionName };
                }, (phyDevice) =>
                {
                    QueueFamilyProperties[] properties = phyDevice.GetQueueFamilyProperties();
                    manager.Logger.LogInformation($"Vulkan硬件设备支持的队列家族数量为{properties.Length}");
                    var result = new List<QueueFamilyIndices>();
                    QueueFamilyIndices index = new QueueFamilyIndices();
                    for (uint i = 0; i < properties.Length; i++)
                    {
                        if (properties[i].QueueFlags.HasFlag(QueueFlags.QueueGraphicsBit))
                        {
                            index.FamilyType |= QueueType.Graphics;
                            if (phyDevice.GetPhysicalDevicePresentationSupport((int)i))
                            {
                                index.FamilyType |= QueueType.Present;
                                index.FamilyIndex = i;
                                result.Add(index);
                                index = new QueueFamilyIndices();
                                continue;
                            }
                        }
                    }
                    return result.ToArray();
                });
                lDevice.InitWorkQueue((device, indeics) =>
                {
                    List<WorkQueue> list = new List<WorkQueue>();
                    foreach (var item in indeics)
                    {
                        if (item.FamilyType == (QueueType.Graphics | QueueType.Present))
                        {
                            Queue queue = device.GetQueue(item.FamilyIndex, 0);
                            var type = QueueType.Graphics | QueueType.Present;
                            WorkQueue work = new WorkQueue(type, item.FamilyIndex, 0, queue);
                            list.Add(work);
                            return list;
                        }
                    }
                    return list;
                });
                lDevice.CreateResourcesCommandPool(lDevice.WorkQueues[0].FamilyIndex);
                var pipeCache = lDevice.CreatePipelineCache();

                var windowOption = new WindowOption() { Height = 768, Width = 1366, Title = "VkSample102", UpdateRate = 120 };
                var window = manager.CreateWindow<Window>("Main", windowOption).ConfigWindow<Window, WindowConfig>();
                window.AddWapperModules(typeof(PipelineModule), typeof(AssetsModule), typeof(RenderPassModule));
                manager.RunWindow(window);
            });
        }

        public void ConfigureServices(IServiceCollection services)
        {
        }

        private static uint DebugReport(DebugReportFlagsEXT flags, DebugReportObjectTypeEXT objectType, ulong @object, UIntPtr location, int messageCode, string layerPrefix, string message, IntPtr userData)
        {
            Console.WriteLine(message);
            return 0;
        }
    }
}
